package com.akjava.akjbetas.vocaloid;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;

import jp.sourceforge.akjrcp.akj_betas.Messages;
import jp.sourceforge.akjrcp.commons.ui.FileDirChoicer;
import jp.sourceforge.akjrcp.commons.ui.AbstractFileDirChoicer.FileStatusChangeEvent;
import jp.sourceforge.akjrcp.commons.ui.AbstractFileDirChoicer.FileStatusChangeListener;
import jp.sourceforge.akjrcp.commons.ui.widget.LayoutDataBuilder;
import jp.sourceforge.akjrcp.commons.ui.widget.WidgetBuilder;
import jp.sourceforge.akjrcp.commons.util.FileNameUtils;
import jp.sourceforge.akjrcp.subtitle.StandardSubObject;
import jp.sourceforge.akjrcp.subtitle.srt.SRTList;
import jp.sourceforge.akjrcp.subtitle.srt.SRTObject;
import jp.sourceforge.akjrcp.subtitle.srt.SRTParser;
import jp.sourceforge.akjrcp.subtitle.srt.TimeData;
import jp.sourceforge.akjrcp.tools.OtherToolsSettingPage;
import jp.sourceforge.akjrcp.ui.param.ParamBoolean;
import jp.sourceforge.akjrcp.ui.param.ParamCheckGroup;
import jp.sourceforge.akjrcp.ui.param.ParamItem;
import jp.sourceforge.akjrcp.ui.param.ParamItemActionListener;
import jp.sourceforge.akjrcp.ui.param.ParamRadioGroup;
import jp.sourceforge.akjrcp.ui.param.ParamText;
import jp.sourceforge.akjrcp.ui.param.ParamTextArea;
import jp.sourceforge.akjrcp.util.ExecutingControler;
import jp.sourceforge.akjrcp.util.ExecutingControler.ExecutingControlButton;

import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.part.ViewPart;

import vocaloid.VSQDumper;
import vocaloid.VocaloidMIDI;
import vocaloid.VocaloidNote;
import vocaloid.VocaloidSystem;
import vocaloid.VocaloidTrack;
import vocaloid.VocaloidUtils;


public class VsqToTxtViewer extends ViewPart {
	public static Log log=LogFactory.getLog(VsqToTxtViewer.class);
	
	public static final String ID = VsqToTxtViewer.class.getName();
	

	private FileDirChoicer inputVsqFileChooser;

	
	private FileDirChoicer outputFileChooser;
	private VsqToTextExecute vsqToTextExecuter;
	
	

	private Label statusLabel;

	
	
private ParamRadioGroup exportMode;
private String MODE_TXT="TXT";
private String MODE_CSV="CSV";
private String MODE_SRT="SRT";



	private Text previewText;

	private ParamCheckGroup columnMode;

	private ParamCheckGroup srtPremeasure;
	public class ExportFileSet implements FileStatusChangeListener{

		public void addList(FileStatusChangeEvent event) {
			String path=event.getFilePath();
			if(!path.equals("")){
				setInputVsq(path);
			}else{
				updateStatus();
			}
			
		}

		public void removeList(FileStatusChangeEvent event) {
			// TODO Auto-generated method stub
			
		}

	
		
	}
	
	public void createPartControl(Composite parent) {
		
		vsqToTextExecuter = new VsqToTextExecute();
		
		parent.setLayout(new GridLayout(1,false));
		
		
		
FileSelected selectedListener=new FileSelected();
		

		
previewText = WidgetBuilder.createTextArea(parent, "");
previewText.setLayoutData(LayoutDataBuilder.fillBothGridData());

Button preview=new Button(parent,SWT.NULL);
preview.setText(Messages.getString("vsqtotext.preview"));
preview.addSelectionListener(new SelectionListener(){
	@Override
	public void widgetDefaultSelected(SelectionEvent e) {
		
	}

	@Override
	public void widgetSelected(SelectionEvent e) {
		String text=toTextData(exportMode.getValue(),inputVsqFileChooser.getAbsoluteFilePath());
		previewText.setText(text);
	}});
		//preview

	Composite s1=createSplitComposite(parent,3,false,new GridData(GridData.FILL_HORIZONTAL));
		
		
		
		 //export type
		 exportMode = new ParamRadioGroup(s1,SWT.NULL,"exportType",Messages.getString("vsqtotext.exportMode"),new String[]{"SRT","TXT","CSV"},new String[]{"SRT","TXT","CSV"},3);
		 exportMode.setValue("SRT");
		 exportMode.setParamItemActionListener(new ParamItemActionListener(){

			
			@Override
			public void paramItemModified(ParamItem item) {
				if(outputFileChooser.getAbsoluteFilePath().length()>0){
					
					String path=FileNameUtils.getChangedExtensionName(outputFileChooser.getAbsoluteFilePath(), exportMode.getValue().toLowerCase());
					outputFileChooser.setFilePath(path);
				}
			}});
		 
		 columnMode=new ParamCheckGroup(s1,SWT.NONE,"columns",Messages.getString("vsqtotext.columns"),
					new String[]{Messages.getString("vsqtotext.column_label"),Messages.getString("vsqtotext.column_phonetics")},2);
		 columnMode.setValue(Messages.getString("vsqtotext.column_label"));
		 //+"+"+Messages.getString("vsqtotext.column_phonetics")
		 //srt dont need up
		
		 srtPremeasure=new ParamCheckGroup(s1,SWT.NONE,"srtPremeasure",Messages.getString("vsqtotext.skip"),
					new String[]{Messages.getString("vsqtotext.skip_premeasure")},2);
		 
		 
		inputVsqFileChooser = new FileDirChoicer(parent,SWT.BORDER,FileDirChoicer.FILE,Messages.getString("vsqtotext.vsq"));
		inputVsqFileChooser.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		inputVsqFileChooser.addFileListChangeListener(selectedListener);
		inputVsqFileChooser.setFilterExtensions(new String[]{"*.vsq"});
		inputVsqFileChooser.addFileListChangeListener(new ExportFileSet());
		
		//inputVsqFileChooser.setFilePath("C:\\Users\\aki\\Documents\\test2.vsq");

		
		
		Composite outputs=WidgetBuilder.createTwoGridLayoutComposite(parent, SWT.NULL);
		outputs.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		Button sameAsInput=new Button(outputs,SWT.NULL);
		sameAsInput.setText(Messages.getString("wav2midi.sameInInput"));
		sameAsInput.addSelectionListener(new SelectionListener(){

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
				
			}

			@Override
			public void widgetSelected(SelectionEvent e) {
				if(!inputVsqFileChooser.getAbsoluteFilePath().equals("")){
					syncInputAndOutput(inputVsqFileChooser.getAbsoluteFilePath(),true);
				}
				
			}
			});
		outputFileChooser = new FileDirChoicer(outputs,SWT.BORDER,FileDirChoicer.SAVE,Messages.getString("wav2midi.export_vsq"),true);
		outputFileChooser.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		outputFileChooser.setFilterExtensions(new String[]{"*.srt","*.txt","*.csv"});
		outputFileChooser.addFileListChangeListener(selectedListener);
		
		
		
		vsqToTextExecuter.addControl(inputVsqFileChooser);

		vsqToTextExecuter.addControl(outputFileChooser);
		
		Composite exec_label=WidgetBuilder.createGridLayoutComposite(parent,SWT.NULL,2, false);
		ExecutingControlButton exec=new ExecutingControlButton(exec_label,SWT.NULL,vsqToTextExecuter,
				Messages.getString("vsqtotext.export_txt"),Messages.getString("cancel"));
		
		statusLabel = new Label(exec_label,SWT.NULL);
		statusLabel.setForeground(new Color(null,new RGB(255,0,0)));
		
		updateStatus();
		
		new DropMonitor(parent);
	}
	

	//xxx
	protected String toTextData(String mode,String input) {
		if(input.length()==0){
			return "";
		}
		boolean skipPremeasure=false;
		if(srtPremeasure.getValue().indexOf(Messages.getString("vsqtotext.skip_premeasure"))!=-1){
			skipPremeasure=true;
		}
		String ret="";
		if(mode==MODE_CSV){
			try {
				StringBuffer buffer=new StringBuffer();
				VocaloidMIDI midi=VocaloidSystem.read(new File(input));
				
				long skipMs=(long) (toSkipSecond(midi)*1000);
				
				List<VocaloidTrack> tracks=midi.getTracks();
				VocaloidTrack track=tracks.get(0);
				List<VocaloidNote> notes=track.getNotes();
				for (int i = 0; i < notes.size(); i++) {
					long start=(long)(VocaloidUtils.tickToSecond(midi.getTempo(), notes.get(i).getStart())*1000);
					long end=(long)(VocaloidUtils.tickToSecond(midi.getTempo(), notes.get(i).getLength())*1000);
					
					if(skipPremeasure){
						start-=skipMs;
						//end-=skipMs;
					}
					
					TimeData stime=new TimeData(start);
					TimeData etime=new TimeData(end);
					String column=columnMode.getValue();
					String text=stime.toString().replace(",", ".")+","+etime.toString().replace(",", ".");
					
					if(column.indexOf(Messages.getString("vsqtotext.column_label"))!=-1){
					text+=","+notes.get(i).getLabel();
					}
					if(column.indexOf(Messages.getString("vsqtotext.column_phonetics"))!=-1){
						
						text+=","+notes.get(i).getPhonetics();
						}
					
				buffer.append(text+"\r\n");
				}
				
				return buffer.toString();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}else if(mode==MODE_SRT){
			try {
				SRTList srts=new SRTList();
				VocaloidMIDI midi=VocaloidSystem.read(new File(input));
				List<VocaloidTrack> tracks=midi.getTracks();
				VocaloidTrack track=tracks.get(0);
				List<VocaloidNote> notes=track.getNotes();
				
				long skipMs=(long) (toSkipSecond(midi)*1000);
				
				for (int i = 0; i < notes.size(); i++) {
					long start=(long)(VocaloidUtils.tickToSecond(midi.getTempo(), notes.get(i).getStart())*1000);
					long end=(long)(VocaloidUtils.tickToSecond(midi.getTempo(), notes.get(i).getLength())*1000);
					
					if(skipPremeasure){
						start-=skipMs;
						//end-=skipMs;
					}
					
					SRTObject srt=new SRTObject();
					srt.setStartTime(start);
					srt.setEndTime(start+end);
					
					String column=columnMode.getValue();
					String text="";
					if(column.indexOf(Messages.getString("vsqtotext.column_label"))!=-1){
					text+=notes.get(i).getLabel();
					}
					if(column.indexOf(Messages.getString("vsqtotext.column_phonetics"))!=-1){
						if(text.length()>0){
							text+=",";
						}
						text+=notes.get(i).getPhonetics();
						}
					
					srt.setText(text);
					srts.add(srt);
				}
				srts.reindex();
				return srts.toString();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}else{
		//TXT
			VSQDumper dumper=new VSQDumper();
			ret=dumper.toDumpText(new File(input));
		}
		return ret;
	}

	private double toSkipSecond(VocaloidMIDI midi) {
		
		
		return VocaloidUtils.tickToSecond(midi.getTempo(),midi.getOffsetTick());
	}

	public class SettingMonitor implements IPropertyChangeListener {

		public void propertyChange(PropertyChangeEvent event) {
			log.info(event.getProperty());
			if (event.getProperty().equals(OtherToolsSettingPage.PATH_ASCII_TEMPORARY)) {
				updateStatus();
			} 
		}
	}
	
	public void setFocus() {
		
	}
	public void updateStatus() {
		//update label.
		if(vsqToTextExecuter.canExecute()){
			if(new File(outputFileChooser.getAbsoluteFilePath()).exists()){
				statusLabel.setText(Messages.getString("wav2midi.warn_overwrite"));
			}else{
			statusLabel.setText("");
			}
		}else{
			if(inputVsqFileChooser.getAbsoluteFilePath().equals("")){
				statusLabel.setText(Messages.getString("vsqtotext.choose_input"));
			}else if(outputFileChooser.getAbsoluteFilePath().equals("")){
				statusLabel.setText(Messages.getString("vsqtotext.choose_output"));
			}
		}
		
		// enable buttons and status.
		vsqToTextExecuter.updateControlSwitch();
	}
	private Composite createSplitComposite(Composite parent,int split,boolean same,Object data){
		Composite composite=new Composite(parent,SWT.NULL);
		composite.setLayout(new GridLayout(split,same));
		if(data!=null){
			composite.setLayoutData(data);
		}
		return composite;
	}
	private ParamTextArea createGridTextAreaGroup(Composite parent,String key,String label,Object data){
		/*Group group=new Group(parent,SWT.NULL);
		group.setText(label);
		group.setLayout(new FillLayout());
		group.setLayoutData(data);
		Text text=new Text(group,SWT.MULTI|SWT.V_SCROLL|SWT.H_SCROLL|SWT.BORDER);
		*/
		
		ParamTextArea text=new ParamTextArea(parent,SWT.NULL,key,label,ParamText.LAYOUT_FILL_BOTH);
		text.setLayoutData(data);
		return text;
	}
	
	private ParamText createLabeldText(Composite parent,String key,String label,Object data){
		ParamText text=new ParamText(parent,SWT.NULL,key,label,ParamText.LAYOUT_FILL_HORIZONTAL);
		if(data!=null){
			text.setLayoutData(data);
		}
		return text;
	}
	
	public class VsqToTextExecute extends ExecutingControler{
		
	
		
		private String outputFileChooser_value;
		
		
		
		private String outputText;
		public void afterExecute() {
			
		}

		@Override
		public void beforeExecute() {

			

			
			
	
			
			outputFileChooser_value=outputFileChooser.getAbsoluteFilePath();
			

			outputText=toTextData(exportMode.getValue(),inputVsqFileChooser.getAbsoluteFilePath());
			previewText.setText(outputText);
		}

		@Override
		public boolean canExecute() {

			return!inputVsqFileChooser.getAbsoluteFilePath().equals("") &&!outputFileChooser.getAbsoluteFilePath().equals("") ;
			
		}

		@Override
		public void cancelExecuting() {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void inExecute() {

			File output=new File(outputFileChooser_value);
			
			
			try {
				FileUtils.writeStringToFile(output, outputText);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			
		}
		
		
	}
	public StandardSubObject[] loadSubtitles(File file){
		if(file==null || !file.exists()){
			return new StandardSubObject[0];
		}
		SRTParser parser=new SRTParser();
		SRTList list;
		try {
			list = parser.parse(new FileReader(file));
			List<StandardSubObject> subList=list.convertStandardSubtitleDataList();
			return subList.toArray(new StandardSubObject[subList.size()]);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		 return new StandardSubObject[0];
	}

	public class FileSelected implements FileStatusChangeListener{

		public void addList(FileStatusChangeEvent event) {
			
			updateStatus();
		}

		public void removeList(FileStatusChangeEvent event) {
			updateStatus();
		}
		
	}
	

	public class DropMonitor extends DropTargetAdapter {
		public DropMonitor(Composite controler){
			Transfer[] types = new Transfer[] { FileTransfer.getInstance() };

			int operations = DND.DROP_MOVE | DND.DROP_COPY;

			DropTarget target2 = new DropTarget(controler, operations);
			target2.setTransfer(types);

			target2.addDropListener(this);
		}
		public void dragEnter(DropTargetEvent event) {
			// log.infodrag enter:"+event.data);
		}

		public void dragOver(DropTargetEvent event) {
			// log.infodrag over:"+event.data);
		}

		public void drop(DropTargetEvent event) {
			//log.info("cancovert:"+isCanConvert());
					
			String files[] = (String[]) event.data;

			
			for (int i = 0; i < files.length; i++) {
				
				if(FileNameUtils.isWaveFile(files[i]) && new File(files[i]).isFile()){
				inputVsqFileChooser.setFilePath(files[i]);
				setInputVsq(files[i]);
				break;	//now first 1 file only
				}else if(FileNameUtils.getExtension(files[i]).toLowerCase().equals("vsq")){
					outputFileChooser.setFilePath(files[i]);
					vsqToTextExecuter.updateControlSwitch();
					break;
				}
			}
			
		}
	}
	
	public void setInput(String path){
		inputVsqFileChooser.setFilePath(path);
		setInputVsq(path);
	}
	


	private void syncInputAndOutput(String path,boolean overwrite){
		String exportPath;
		
		if(exportMode.getValue()==MODE_SRT){
			exportPath=FileNameUtils.getChangedExtensionName(new File(path), "srt",true);
		}else if(exportMode.getValue()==MODE_CSV){
			exportPath=FileNameUtils.getChangedExtensionName(new File(path), "csv",true);
		}else{
			exportPath=FileNameUtils.getChangedExtensionName(new File(path), "txt",true);
		}
		
		if(!new File(exportPath).exists() || overwrite){//dont overwrite automatic
			outputFileChooser.setFilePath(exportPath);
		}
		updateStatus();
	}
	private void setInputVsq(String path) {
	
		syncInputAndOutput(path,false);
		
		updateStatus();
	}
		
}